{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ae913556-ce9d-49ac-ba11-ed11e5ffd2fc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[229 224 220 ... 220 217 222]\n",
      " [226 219 212 ... 219 218 213]\n",
      " [223 223 223 ... 213 213 215]\n",
      " ...\n",
      " [233 232 232 ... 224 225 225]\n",
      " [233 232 231 ... 225 226 226]\n",
      " [233 232 231 ... 225 226 227]]\n",
      "[[ 27  28 151 151]]\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'y' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_50368/80698488.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     15\u001b[0m \u001b[0mfaces\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mface_cascade\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdetectMultiScale\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mimg_gray\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     16\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfaces\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0mimg_new\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mimg_gray\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0my\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mh\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mw\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     18\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfaces\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     19\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'y' is not defined"
     ]
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import cv2 as cv\n",
    "\n",
    "img = cv.imread(\"Stephen Amell_4087 (35).jpg\")\n",
    "img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)\n",
    "print(img_gray)\n",
    "img_gray = cv.equalizeHist(img_gray)  # 把图像的范围拉开\n",
    "\n",
    "# 1. 创建级联分类器\n",
    "face_cascade = cv.CascadeClassifier()\n",
    "# 2. 引入训练好的可用于人脸识别的级联分类器模型\n",
    "face_cascade.load(\"haarcascade_frontalface_alt.xml\")\n",
    "# 3. 用此级联分类器识别图像中的所有人脸信息，返回一个包含有所有识别的人联系系的列表\n",
    "# 列表中每一个元素包含四个值：面部左上角的坐标(x,y) 以及面部的宽和高(w,h)\n",
    "faces = face_cascade.detectMultiScale(img_gray)\n",
    "print(faces)\n",
    "img_new=img_gray[y:y+h,x:x+w]\n",
    "print(faces)\n",
    "\n",
    "# 4. 为图像中的所有面部画框\n",
    "for (x, y, w, h) in faces:\n",
    "    cv.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)\n",
    "    #img_new=img_gray[y:y+h,x:x+w]\n",
    "    cv.putText(img, # 要显示字体的图片\n",
    "              \"wgz\", # 要显示的内容\n",
    "              (x,y-10), # 要显示的位置\n",
    "              cv.FONT_HERSHEY_SIMPLEX, # 要使用的字体 -> 一般英文字体\n",
    "              1, # 字体放大倍数\n",
    "              (0,255,0), # 字体颜色\n",
    "              2) # 字体线条粗细\n",
    "\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.imshow(cv.cvtColor(img_new, cv.COLOR_BGR2RGB))\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f1ff077f-51c4-4e94-95db-ca2080734fb4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple/\n",
      "Collecting opencv-contrib\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/7b/b9/bc8b30fd9a4d6e96e3b91b168e657892b238b80d35b688d287cd6c2eb5b6/opencv_contrib-1.0.0.14-py3-none-any.whl (7.3 kB)\n",
      "Collecting opencv-contrib-python\n",
      "  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/34/45/c8bc145b1541d1fbbf25d5494cd76453d9855971cfe571b9ad7e13cdb4c8/opencv_contrib_python-4.6.0.66-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (67.1 MB)\n",
      "     |████████████████████████████████| 67.1 MB 644 kB/s            \n",
      "\u001b[?25hRequirement already satisfied: numpy>=1.14.5 in /opt/conda/lib/python3.9/site-packages (from opencv-contrib-python->opencv-contrib) (1.19.5)\n",
      "Installing collected packages: opencv-contrib-python, opencv-contrib\n",
      "Successfully installed opencv-contrib-1.0.0.14 opencv-contrib-python-4.6.0.66\n"
     ]
    }
   ],
   "source": [
    "!pip install opencv-contrib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "92479cb0-07f1-4dde-9982-3a05489a3fe5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "已生成X，结构: (1066, 1024)\n",
      "已生成Y, 结构: (1066,)\n",
      "0.684375\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.svm import SVC\n",
    "import cv2 as cv\n",
    "import os\n",
    "import pickle\n",
    "############################## 获取人的面部图像并保存 ##############################\n",
    "X=[]\n",
    "Y=[]\n",
    "for f in os.listdir('train/'):\n",
    "    if \"ipynb_checkpoints\" not in f:\n",
    "        #print(f)\n",
    "        img = cv.imread('train/'+f) # 以灰度图读入\n",
    "        img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)\n",
    "        img_gray = cv.equalizeHist(img_gray)  # 把图像的范围拉开\n",
    "        # 1. 创建级联分类器\n",
    "        face_cascade = cv.CascadeClassifier()\n",
    "        # 2. 引入训练好的可用于人脸识别的级联分类器模型\n",
    "        face_cascade.load(\"haarcascade_frontalface_alt.xml\")\n",
    "        # 3. 用此级联分类器识别图像中的所有人脸信息，返回一个包含有所有识别的人联系系的列表\n",
    "        # 列表中每一个元素包含四个值：面部左上角的坐标(x,y) 以及面部的宽和高(w,h)\n",
    "        faces = face_cascade.detectMultiScale(img_gray)\n",
    "        for (x, y, w, h) in faces:\n",
    "            img_new=img_gray[y:y+h,x:x+w]\n",
    "        new_img = cv.resize(img_new, (32, 32), interpolation=cv.INTER_NEAREST)\n",
    "        new_img = new_img.reshape(-1)\n",
    "        X.append(new_img)\n",
    "        # 下面代码从以上这种完整路径中首先获得按照/分割的最后一个元素，也就是文件名Chris Pratt_722 (41).jpg\n",
    "        # 然后再获得按照.分割的数组中的第一个元素，也就是 Chris Pratt\n",
    "        label= f.split(os.path.sep)[-1].split('_')[0]\n",
    "        Y.append(label)\n",
    "    else:\n",
    "        continue\n",
    "#X=np.array(X)\n",
    "#Y=np.array(Y)\n",
    "#利用pickle将X，Y封装成包\n",
    "with open(\"X\",'wb') as f:\n",
    "    pickle.dump(X,f)\n",
    "    print(\"已生成X，结构:\",np.shape(X))\n",
    "with open(\"Y\",'wb') as f:\n",
    "    pickle.dump(Y,f)\n",
    "    print(\"已生成Y, 结构:\",np.shape(Y))\n",
    "############################## 训练模型 ##############################\n",
    "with open(\"X\",'rb') as f:\n",
    "    X=pickle.load(f)\n",
    "with open(\"Y\",'rb') as f:\n",
    "    Y=pickle.load(f)\n",
    "#X=PCA(0.9).fit_transform(X)\n",
    "# 注意此题目只为熟练PCA的使用，真正应用环境中因为还需要对未知数据进行predict\n",
    "# 所以要用到pca的模型本身，可写成\n",
    "pca=PCA(0.9).fit(X)#<-- 这样pca就可以被pickle或者直接被之后的代码所使用了\n",
    "X=pca.transform(X)\n",
    "X_train,X_test,Y_train,Y_test=train_test_split(X,Y,test_size=0.3)\n",
    "\n",
    "#SVM模型\n",
    "svc=SVC()\n",
    "svc.fit(X_train,Y_train)\n",
    "\n",
    "#获得算法准确率\n",
    "acc=svc.score(X_test,Y_test)\n",
    "print(acc)\n",
    "\n",
    "#封装模型\n",
    "with open(\"svc\",'wb') as f:\n",
    "    pickle.dump(svc,f)\n",
    "############################## 预测数据 ##############################"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "id": "1fb11e8b-fc1f-420b-a744-7439eb59590d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.740625"
      ]
     },
     "execution_count": 99,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "############################## 训练模型 ##############################\n",
    "with open(\"X\",'rb') as f:\n",
    "    X=pickle.load(f)\n",
    "with open(\"Y\",'rb') as f:\n",
    "    Y=pickle.load(f)\n",
    "#X=PCA(0.9).fit_transform(X)\n",
    "# 注意此题目只为熟练PCA的使用，真正应用环境中因为还需要对未知数据进行predict\n",
    "# 所以要用到pca的模型本身，可写成\n",
    "pca=PCA(0.9).fit(X)#<-- 这样pca就可以被pickle或者直接被之后的代码所使用了\n",
    "X=pca.transform(X)\n",
    "X_train,X_test,Y_train,Y_test=train_test_split(X,Y,test_size=0.3)\n",
    "\n",
    "#SVM模型\n",
    "svc=SVC(C=3.85)\n",
    "svc.fit(X_train,Y_train)\n",
    "\n",
    "#获得算法准确率\n",
    "acc=svc.score(X_test,Y_test)\n",
    "acc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "906b4107-d15c-42f4-8820-642634fe62dd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "acc 0.6\n"
     ]
    }
   ],
   "source": [
    "from sklearn.ensemble import RandomForestClassifier\n",
    "# 3. 创建随机森林模型\n",
    "clf = RandomForestClassifier()\n",
    "# 相当于 clf = RandomForestClassifier(n_estimators=100)\n",
    "clf.fit(X_train, Y_train)\n",
    "\n",
    "# 4. 获得算法的准确率\n",
    "acc = clf.score(X_test, Y_test)\n",
    "print(\"acc\", acc)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0b141f6b-c1e5-4a01-8eac-c7aab914534f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始搜索最佳K:\n",
      "746\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.528125"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "# 3. 搜索最佳K\n",
    "print(\"开始搜索最佳K:\")\n",
    "print(X_train.shape[0])\n",
    "acc_list=[]\n",
    "max_test=len(X_train)\n",
    "for k in range(1,max_test+1):\n",
    "    clf = KNeighborsClassifier(n_neighbors=k) # 1. 创建分类器\n",
    "    clf.fit(X_train, Y_train)                 # 2. fit\n",
    "    acc = clf.score(X_test, Y_test)           # 3. score\n",
    "    #print(\"K={0} 准确率: {1:.2f}%\".format(k, acc * 100))\n",
    "    acc_list.append(acc) # 纪律所有的准确率\n",
    "\n",
    "# 保存最大准确率对应的knn\n",
    "max_acc_k=np.argmax(acc_list)+1 # 利用最大准确率的位置得到对应的k：max_acc_k\n",
    "# 训练出 max_acc_k 对应的 knn 模型\n",
    "clf = KNeighborsClassifier(n_neighbors=max_acc_k).fit(X_train, Y_train)\n",
    "acc=clf.score(X_test, Y_test)\n",
    "acc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "0d5ff7b3-725a-429e-9fb2-875f5c9990bf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Chris Pratt' 'Chris Pratt' 'Jason Momoa' 'Jason Momoa' 'Jason Momoa'\n",
      " 'Jason Momoa' 'margot robbie' 'margot robbie' 'margot robbie'\n",
      " 'margot robbie' 'Robert Downey Jr' 'Robert Downey Jr' 'Robert Downey Jr'\n",
      " 'Stephen Amell' 'Stephen Amell' 'Stephen Amell' 'Stephen Amell']\n"
     ]
    }
   ],
   "source": [
    "############################## 预测数据 ##############################\n",
    "test=[]\n",
    "for f in os.listdir('test/'):\n",
    "    if \"ipynb_checkpoints\" not in f:\n",
    "        #print(f)\n",
    "        img = cv.imread('test/'+f) # 以灰度图读入\n",
    "        img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)\n",
    "        img_gray = cv.equalizeHist(img_gray)  # 把图像的范围拉开\n",
    "        # 1. 创建级联分类器\n",
    "        face_cascade = cv.CascadeClassifier()\n",
    "        # 2. 引入训练好的可用于人脸识别的级联分类器模型\n",
    "        face_cascade.load(\"haarcascade_frontalface_alt.xml\")\n",
    "        # 3. 用此级联分类器识别图像中的所有人脸信息，返回一个包含有所有识别的人联系系的列表\n",
    "        # 列表中每一个元素包含四个值：面部左上角的坐标(x,y) 以及面部的宽和高(w,h)\n",
    "        faces = face_cascade.detectMultiScale(img_gray)\n",
    "        for (x, y, w, h) in faces:\n",
    "            img_new=img_gray[y:y+h,x:x+w]\n",
    "        new_img = cv.resize(img_new, (32, 32), interpolation=cv.INTER_NEAREST)\n",
    "        new_img = new_img.reshape(-1)\n",
    "        test.append(new_img)\n",
    "test=np.array(test)\n",
    "test=pca.transform(test)\n",
    "with open(\"svc\",'rb') as f:\n",
    "    svc=pickle.load(f)\n",
    "pdt=svc.predict(test)\n",
    "print(pdt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7ef3aa3b-0d79-4184-b67a-3b9475deca9d",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
